/*
 * SplittingTree.cpp
 *
 * Copyright 2012 Fabian Wenzelmann
 *
 * This file is part of Recognition-Procedures-for-Boolean-Functions.
 *
 * Recognition-Procedures-for-Boolean-Functions is free software: you
 * can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Recognition-Procedures-for-Boolean-Functions is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Recognition-Procedures-for-Boolean-Functions.
 *
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include "bfr/lpbCombinatorial/SplittingTree.hpp"

#include <algorithm>
#include <queue>
#include <utility>
#include <vector>

#include "bfr/OccurrencePattern.hpp"
#include "bfr/ClauseSet.hpp"
#include "bfr/CoefficientType.hpp"

#include "bfr/lpbCombinatorial/SplittingTreeNode.hpp"
#include "bfr/lpbCombinatorial/VariableSetting.hpp"
#include "bfr/lpbCombinatorial/TreeContext.hpp"

namespace bfr {

SplittingTree::~SplittingTree() {
    delete vs;
    // delete all nodes
    size_t size = context->size();
    for (size_t i = 0; i < size; i++) {
        TreeContext::const_col_iterator colE = context->columnEnd(i);
        for (TreeContext::const_col_iterator it = context->columnBegin(i);
             it != colE; it++) {
            delete *it;
        }
    }
    delete context;
}

SplittingTree::SplittingTree(ClauseSet *d, size_t variableCount)
	: root(NULL),
	  vs(new VariableSetting(d)),
	  minCulprit(0),
	  maxCulprit(0) {
    size_t maxVal = -1;
    if (variableCount == maxVal) {
        variableCount = d->getMaxLiteralId() + 1;
    }
    context = new TreeContext(variableCount);
    std::vector<OccurrencePattern*> *patterns = vs->getOrderedPatterns();
    // TODO, as in SplittingTreeNode: not happy with that...
    root = new SplittingTreeNode(0, 0, d, patterns, context,
            SplittingNodeType::MAIN_NODE, SplittingNodeContent());
    root->calcIsFinal();
}

SplittingTreeNode* SplittingTree::getRoot() const {
    return root;
}

TreeContext* SplittingTree::getContext() const {
    return context;
}

size_t SplittingTree::size() const {
    return context->size();
}

SplittingTreeNode *SplittingTree::getMinCulprit() const {
    return minCulprit;
}

SplittingTreeNode *SplittingTree::getMaxCulprit() const {
    return maxCulprit;
}

bool SplittingTree::getDNFValue(ClauseSet *dnf) const {
    return dnf->size() != 0;
}

VariableSetting* SplittingTree::getVariableSetting() const {
    return vs;
}

size_t SplittingTree::numFinalNodes() const {
    size_t result = 0;

    const size_t s = context->size();

    for (size_t i = 0; i < s; i++) {
        TreeContext::const_col_iterator itEnd = context->columnEnd(i);
        for (TreeContext::const_col_iterator it = context->columnBegin(i);
             it != itEnd;
             it++) {
            if ((*it)->isFinal())
                result++;
        }
    }
    return result;
}

size_t SplittingTree::numFinalTrueNodes() const {
    size_t result = 0;

    const size_t s = context->size();

    for (size_t i = 0; i < s; i++) {
        TreeContext::const_col_iterator itEnd = context->columnEnd(i);
        for (TreeContext::const_col_iterator it = context->columnBegin(i);
             it != itEnd;
             it++) {
	  if ((*it)->isFinal() && ((*it)->getDNF()->size() == 0))//it's a true node
                result++;
        }
    }
    return result;
}

}
